import logging
import boto3
from botocore.exceptions import ClientError
import os
from functools import lru_cache
from fastapi import Depends
from typing import Annotated
from config import get_settings, Settings
from botocore.client import Config


def get_client(settings: Settings):
    svc = boto3.client(
        "s3",
        endpoint_url=settings.aws_endpoint_url_s3,
        config=Config(s3={"addressing_style": "virtual"}),
    )
    return svc


def head_object(s3_client: any, bucket: str, object_name: str):
    try:
        response = s3_client.head_object(Bucket=bucket, Key=object_name)
        print("head_object response:", response)
    except ClientError as e:
        logging.error(e)
        return False
    return True

def upload_file(
    s3_client: any,
    file_name,
    bucket,
    object_name=None,
):
    """Upload a file to an S3 bucket

    :param file_name: File to upload
    :param bucket: Bucket to upload to
    :param object_name: S3 object name. If not specified then file_name is used
    :return: True if file was uploaded, else False
    """

    # If S3 object_name was not specified, use file_name
    if object_name is None:
        object_name = os.path.basename(file_name)

    # Upload the file
    try:
        response = s3_client.upload_file(file_name, bucket, object_name)
        print("upload_file response:", response)
    except ClientError as e:
        logging.error(e)
        return False
    return True


def download_file(
    s3_client: any,
    file_name: str,
    bucket: str,
    save_url: str | None = None,
):
    """Download a file to an S3 bucket

    :param file_name: File to upload
    :param bucket: Bucket to upload to
    :param save_url: downloaded_file_url
    :return: True if file was uploaded, else False
    """

    # If S3 object_name was not specified, use file_name
    if save_url is None:
        save_url = os.path.basename(file_name)

    # Upload the file
    try:
        response = s3_client.download_file(bucket, file_name, save_url)
        print("download_file response:", response)
    except ClientError as e:
        logging.error(e)
        return False
    return True


def create_presigned_url(s3_client: any, bucket_name, object_name, expiration=3600):
    """Generate a presigned URL to share an S3 object

    :param bucket_name: string
    :param object_name: string
    :param expiration: Time in seconds for the presigned URL to remain valid
    :return: Presigned URL as string. If error, returns None.
    """

    # Generate a presigned URL for the S3 object
    try:
        response = s3_client.generate_presigned_url(
            "get_object",
            Params={"Bucket": bucket_name, "Key": object_name},
            ExpiresIn=expiration,
        )
    except ClientError as e:
        logging.error(e)
        return None

    # The response contains the presigned URL
    return response
